package cn.bud.msgbus.server.bean;

import com.zl9c.general.common.exception.MethodNotSupportException;
import com.zl9c.general.common.exception.ParamErrorException;
import com.zl9c.general.utils.NumberUtils;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * BusURL
 *
 * @author hxj
 * @version 1.0
 * @description
 * @date 2024-07-15 9:27
 */
@Data
public class BusURL {

    private String url;
    private Protocol protocol;

    private String ip;
    private int port;

    public BusURL(String url) {
        this.url = url;
        parseUrl(url);
    }

    private void parseUrl(String url) {
        if  (StringUtils.isBlank(url)) {
            protocol = Protocol.JVM;
            return;
        }
        int index = url.indexOf(":");
        String protocolName = url.substring(0,index);
        protocol = Protocol.findEnum(protocolName);
        if (protocol == null) {
            throw new MethodNotSupportException("不支持的协议类型："+protocolName+", 总线地址："+url);
        }
        if (!url.startsWith("//", index+1)) {
            throw new MethodNotSupportException("总线地址解析异常，不支持的地址协议头。总线地址："+url);
        }
        ip = readIp(url, index+3);
        port = readPort(url, index+3+ip.length());
    }

    private static int readPort(String url, int index) {
        if (url.length() == index) {
            return 80;
        }
        char ch = url.charAt(index);
        if (ch == '/') {
            return 80;
        }else if (ch != ':') {
            throw new ParamErrorException("总线地址解析异常，无法读取地址中的端口，原总线地址："+url);
        }
        index++;
        String portStr = "";
        do {
            ch = url.charAt(index);
            if (ch < '0' || ch>'9') {
                break;
            }
            portStr = portStr+ch;
            index++;
        }while (index < url.length());
        if (StringUtils.isBlank(portStr)) {
            throw new ParamErrorException("总线地址解析异常，无法读取地址中的端口，原总线地址："+url);
        }
        Integer port = NumberUtils.parseInt(portStr);
        if (port == null || port > 65535) {
            throw new ParamErrorException("总线地址解析异常，端口范围异常，原总线地址："+url);
        }
        return port;
    }

    private static String readIp(String url, int index) {
        if (url.startsWith("localhost", index)) {
            return "localhost";
        }
        if (url.length() <= index) {
            throw new ParamErrorException("总线地址异常，无法解析IP， 原总线地址："+url);
        }
        StringBuilder sb = new StringBuilder();
        do {
            char ch = url.charAt(index);
            if (ch == '.' || ch == '_'
                    || (ch >= '0' && ch <= '9')
                    || (ch >= 'A' && ch <= 'Z')
                    || (ch >= 'a' && ch <= 'z')
            ) {
                sb.append(ch);
            }else {
                break;
            }
            index++;
        }while (index < url.length());
        String ip = sb.toString();
//        if (!Validator.isIpv4(ip)) {
//            throw new ParamErrorException("总线地址异常，IP解析异常："+ip+"，原地址："+url);
//        }
        return ip;
    }

    public boolean isLocalServer(Integer port) {

        if (this.port == port ) {
            if("localhost".equalsIgnoreCase(ip)) {
                return true;
            }
            if("127.0.0.1".equalsIgnoreCase(ip)) {
                return true;
            }
            try {
                InetAddress inetAddress = Inet4Address.getLocalHost();
                String localHost = inetAddress.getHostAddress();
                if (localHost.equals(ip)) {
                    return true;
                }
            } catch (UnknownHostException e) {
            }
        }
        return false;
    }

    public boolean isHttp() {
        return Protocol.HTTP.equals(protocol) || Protocol.HTTPS.equals(protocol);
    }

    public enum Protocol {
        JVM,
        HTTP,
        HTTPS,
        TCP,
        WEBSOCKET;

        public static Protocol findEnum(String protocol) {
            for (Protocol value : values()) {
                if (value.name().equalsIgnoreCase(protocol)) {
                    return value;
                }
            }
            return null;
        }
    }
}
